package com.hmdp.config.bloomfilter;

import cn.hutool.core.util.HashUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.BitSet;
import java.util.List;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class RedisBloomFilter {
    private final StringRedisTemplate stringRedisTemplate;
    private final String redisKey;
    private final int bitSize;
    private final List<ToIntFunction<String>> hashFunctions;

    /**
     * @param redisTemplate Redis操作模板
     * @param redisKey      存储位图的Redis键名
     * @param expectedItems 预计存放元素数量
     * @param falsePositiveRate 误判率 (0-1)
     */
    public RedisBloomFilter(StringRedisTemplate stringRedisTemplate,
                           String redisKey, 
                           long expectedItems, 
                           double falsePositiveRate) {
        this.stringRedisTemplate = stringRedisTemplate;
        this.redisKey = redisKey;
        this.bitSize = calculateBitSize(expectedItems, falsePositiveRate);
        this.hashFunctions = generateHashFunctions(bitSize);
    }

    // 计算需要的位图大小
    private int calculateBitSize(long n, double p) {
        return (int) (-n * Math.log(p) / (Math.log(2) * Math.log(2)));
    }

    // 生成哈希函数
    private List<ToIntFunction<String>> generateHashFunctions(int bitSize) {
        return IntStream.range(0, 5) // 使用5个哈希函数
                .mapToObj(i -> (ToIntFunction<String>) s -> 
                        Math.abs(HashUtil.murmur32(s.getBytes()) % bitSize))
                .collect(Collectors.toList());
    }

    // 添加元素
    public void add(String item) {
        hashFunctions.forEach(func -> {
            int bitIndex = func.applyAsInt(item);
            stringRedisTemplate.opsForValue().setBit(redisKey, bitIndex, true);
        });
    }

    // 检查元素是否存在
    public boolean contains(String item) {
        return hashFunctions.stream().allMatch(func -> 
                Boolean.TRUE.equals(
                    stringRedisTemplate.opsForValue().getBit(redisKey, func.applyAsInt(item))
                )
        );
    }

    // 初始化布隆过滤器（清空数据）
    public void reset() {
        stringRedisTemplate.delete(redisKey);
    }
}